package com.citywithincity.web.request;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import com.citywithincity.utils.ClassUtil;
import com.citywithincity.utils.JsonUtil;
import com.damai.error.ApiError;

public class RequestDataFactory {

	private static final RequestToMap REQUEST_TO_MAP = new RequestToMap();
	private static final RequestGetRequest REQUEST_GET_REQUEST = new RequestGetRequest();

	static class RequestToMap implements IRequestData {

		@Override
		public Object getValue(HttpServletRequest request, String name) {
			Map<String, Object> result = new HashMap<String, Object>();
			for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
				result.put(entry.getKey(), entry.getValue()[0]);
			}
			return result;
		}

	}

	static class String2Bool implements IRequestData {

		@Override
		public Object getValue(HttpServletRequest request, String name) {
			String value = request.getParameter(name);
			return value == null ? Boolean.FALSE : Boolean.valueOf(value);
		}

	}

	static class String2Map implements IRequestData {

		@Override
		public Object getValue(HttpServletRequest request, String name) {
			String value = request.getParameter(name);
			if(value == null){
				return null;
			}
			try {
				return JsonUtil.read(value);
			} catch (IOException e) {
				return null;
			}
		}

	}

	static class RequestGetRequest implements IRequestData {

		@Override
		public Object getValue(HttpServletRequest request, String name) {
			return request;
		}

	}

	static class RequestGetBean implements IRequestData {
		private Class<?> type;
		private Field[] fields;

		public RequestGetBean(Class<?> type) {
			this.type = type;
			fields = ClassUtil.getFields(type);
			for (Field field : fields) {
				field.setAccessible(true);
			}
		}

		@Override
		public Object getValue(HttpServletRequest request, String name) {

			try {
				final Field[] fields = this.fields;
				final Class<?> type = this.type;

				Object obj = type.newInstance(); // 创建 JavaBean 对象
				// 给 JavaBean 对象的属性赋值

				for (Field field : fields) {
					String propertyName = field.getName();
					// 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
					String value = request.getParameter(propertyName);
					if (value != null) {
						// 转化为这里的类型
						IRequestData data = cached.get(field.getType());
						field.set(obj, data.getValue(request, propertyName));
					}
				}
				return obj;
			} catch (Exception e) {
//				throw new ApiError("参数错误" + e.getMessage());
				throw new ApiError(e.getMessage());
			}

		}

	}

	private static Map<Class<?>, IRequestData> cached = new HashMap<Class<?>, IRequestData>();

	static {
		cached.put(int.class, new String2int());
		cached.put(Integer.class, new String2Integer());
		cached.put(Long.class, new String2Long());
		cached.put(String.class, new String2String());
		cached.put(boolean.class, new String2boolean());
		cached.put(Boolean.class, new String2Bool());
		cached.put(Map.class, new String2Map());
	}

	/**
	 * 
	 * @param type
	 * @return
	 */
	public static IRequestData create(Class<?> type) {
		if (type.isPrimitive() || type.getName().startsWith("java.lang")) {
			IRequestData data = cached.get(type);
			if (data == null) {
				throw new RuntimeException("不支持的参数类型" + type.getName());
			}
			return data;
		} else if (Map.class.isAssignableFrom(type)) {
			return REQUEST_TO_MAP;
		} else if (HttpServletRequest.class == type) {
			return REQUEST_GET_REQUEST;
		} else {
			// bean
			return new RequestGetBean(type);
			// throw new RuntimeException("不支持的参数类型"+type.getName());
		}
	}
}
